package com.atwulidun.hashtable;

import java.util.Scanner;

public class HashTableDemo {
    public static void main(String[] args) {
        // 一、首先创建一个HashTable
        HashTable hashTable = new HashTable(10);
        // 二、开启输入流
        Scanner scanner = new Scanner(System.in);
        // 三、定义接收的字符串
        String key = "";
        // 四、定义一个变量控制循环
        boolean loop = true;

        while (loop) {
            System.out.println("添加员工:add");
            System.out.println("删除员工:del");
            System.out.println("查找员工:sear");
            System.out.println("显示员工:list");
            System.out.println("退出程序:exit");
            key = scanner.next();
            switch (key) {
                case "add":
                    // 提示输入员工的id号和姓名
                    System.out.println("请输入员工的id:");
                    int id = scanner.nextInt();
                    System.out.println("请输入员工的姓名:");
                    String name = scanner.next();
                    // 创建一个员工
                    Emp emp = new Emp(id, name);
                    hashTable.add(emp);
                    break;
                case "del":
                    // 提示输入要删除的员工id号
                    System.out.println("请输入要删除的员工id:");
                    int no = scanner.nextInt();
                    if (hashTable.delete(no)) {
                        System.out.println("删除成功！");
                    } else {
                        System.out.println("删除失败！");
                    }
                    break;
                case "sear":
                    // 提示输入要查找的员工id号
                    System.out.println("请输入要删除的员工id:");
                    int idNo = scanner.nextInt();
                    if (hashTable.search(idNo) == null) {
                        System.out.println("要查找的员工不存在！");
                    } else {
                        System.out.println("要查找的员工信息为：");
                        System.out.println(hashTable.search(idNo));
                    }
                    break;
                case "list":
                    System.out.println("所有员工信息如下所示：");
                    hashTable.list();
                    break;
                case "exit":
                    scanner.close();
                    loop = false;
                    System.out.print("程序退出，谢谢使用！");
                    break;
            }
        }
    }
}

// 一、首先创建员工类
class Emp {
    private int no;
    private String name;
    private Emp next;// next默认为null

    public Emp(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Emp getNext() {
        return next;
    }

    public void setNext(Emp next) {
        this.next = next;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}

// 二、创建一个EmpLinkedList类
class EmpLinkedList {
    // 定义一个头结点，初始值为null
    private Emp head;

    // 增加员工的方法
    public void add(Emp emp) {
        if (head == null) {
            head = emp;
            return;
        }
        Emp temp = head;
        // 特别注意：以下的这种写法是错误的：因为当temp == null时，虽然把emp赋值给了temp，但是最后一个结点的next仍然是等于null的！！！！！！！！！！！！
//        while (temp != null) {
//            temp = temp.getNext();
//        }
//        temp = emp;
        while (temp.getNext() != null) {
            temp = temp.getNext();
        }
        temp.setNext(emp);
    }

    // 根据id删除员工的方法(首先要调用查找的方法确定要删除的员工是否存在；删除成功返回true，删除失败返回false)
    public boolean delete(int id) {
        if (search(id) == null) {
            // 找不到相应的员工
            return false;
        } else {
            // 若要删除的是头结点，则把头结点直接指向下一个结点即可
            if (search(id) == head) {
                head = head.getNext();
            } else {
                // 若要删除的不是头结点，则要找到待删除结点的前一个结点
                Emp temp = head;
                while (temp.getNext().getNext() != null) {
                    // 这里面判断的只能是第一个结点和最后一个结点中间的结点
                    // 如果if的判断条件一直都不成立，那就说明要删除的是最后一个结点，此时temp.getNext().getNext() != null成立，跳出了while循环
                    if (temp.getNext() == search(id)) {
                        break;
                    }
                    temp = temp.getNext();
                }
                temp.setNext(temp.getNext().getNext());
            }
            // 删除成功返回true
            return true;
        }
    }

    // 根据id查找员工的方法(链表为空或者是找不到，则返回null)
    public Emp search(int id) {
        Emp temp = head;
        while (temp != null) {
            if (temp.getNo() == id) {
                break;
            }
            temp = temp.getNext();
        }
        return temp;
    }

    // 根据链表编号显示该条链表上员工的信息
    public void list(int listNo) {
        if (head == null) {
            System.out.println("第" + (listNo + 1) + "条链表为空！");
        } else {
            System.out.println("第" + (listNo + 1) + "条链表的信息为：");
            Emp temp = head;
            while (temp != null) {
                System.out.printf("编号：%d，姓名：%s\n", temp.getNo(), temp.getName());
                temp = temp.getNext();
            }
        }
    }
}

// 三、创建一个HashTable类
class HashTable {
    // 创建一个一位数组，数组里面放的是EmpLinkedList链表
    private final EmpLinkedList[] empLinkedListArray;
    private final int size;

    // 构造方法
    public HashTable(int size) {
        // 对size进行初始化
        this.size = size;
        // 对数组进行初始化
        empLinkedListArray = new EmpLinkedList[size];
        // 最最重要的是要对数组里面的链表进行初始化，不然的话会报空指针异常！！！！！！！！！！！！！！
        for (int i = 0; i < size; i++) {
            empLinkedListArray[i] = new EmpLinkedList();
        }
    }

    // 添加员工的方法
    public void add(Emp emp) {
        // 首先判断该员工要加入哪条链表
        int hashVal = getHash(emp.getNo());
        // 再调用相应链表的add方法即可
        empLinkedListArray[hashVal].add(emp);
    }

    // 删除员工的方法
    public boolean delete(int no) {
        // 首先找到要删除的员工在哪条链表
        int hashVal = getHash(no);
        // 再调用相应链条的delete方法
        return empLinkedListArray[hashVal].delete(no);
    }

    // 查找员工的方法
    public Emp search(int no) {
        // 首先找到要删除的员工在哪条链表
        int hashVal = getHash(no);
        // 再调用相应链条的search方法
        return empLinkedListArray[hashVal].search(no);
    }

    // 打印hashTable的方法
    public void list() {
        for (int i = 0; i < size; i++) {
            empLinkedListArray[i].list(i);
        }
    }

    // 定义一个获取hash值的方法
    public int getHash(int no) {
        return no % size;
    }
}
